﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Model;

public static class Data
{
    public const string DATA_FOLDER = "Data";
    public const string RECITATIONS_FOLDER = "Audio";
    public const string TRANSLATIONS_FOLDER = "Translations";
    public const string OFFLINE_TRANSLATIONS_FOLDER = "Translations/Offline";

    // quran text from http://tanzil.net
    public static Book BuildSimplifiedBook(SimplificationSystem simplification_system)
    {
        Book book = LoadAndSimplifyBook(DATA_FOLDER + "/" + "quran-uthmani.txt", simplification_system);
        if (book != null)
        {
            LoadRecitationInfos(book);
            LoadTranslationInfos(book);
            LoadTranslations(book);
            LoadWordMeanings(book);
            LoadRootWords(book);
            LoadWordRoots(book);
        }
        return book;
    }

    // translations info from http://tanzil.net
    public static void LoadTranslationInfos(Book book)
    {
        book.TranslationInfos = new Dictionary<string, TranslationInfo>();
        string filename = OFFLINE_TRANSLATIONS_FOLDER + "/" + "metadata.txt";
        if (File.Exists(filename))
        {
            using (StreamReader reader = File.OpenText(filename))
            {
                string line = reader.ReadLine(); // skip header row
                while ((line = reader.ReadLine()) != null)
                {
                    string[] parts = line.Split('\t');
                    if (parts.Length >= 4)
                    {
                        TranslationInfo translation = new TranslationInfo();
                        translation.Url = "?transID=" + parts[0] + "&type=" + TranslationInfo.FileType;
                        translation.Flag = parts[1];
                        translation.Language = parts[2];
                        translation.Translator = parts[3];
                        translation.Name = parts[2] + " - " + parts[3];
                        book.TranslationInfos.Add(parts[0], translation);
                    }
                }
            }
        }
    }

    // recitation infos from http://www.everyayah.com
    public static void LoadRecitationInfos(Book book)
    {
        book.RecitationInfos = new Dictionary<string, RecitationInfo>();
        string filename = RECITATIONS_FOLDER + "/" + "metadata.txt";
        if (File.Exists(filename))
        {
            using (StreamReader reader = File.OpenText(filename))
            {
                string line = reader.ReadLine(); // skip header row
                while ((line = reader.ReadLine()) != null)
                {
                    string[] parts = line.Split('\t');
                    if (parts.Length >= 4)
                    {
                        RecitationInfo recitation = new RecitationInfo();
                        recitation.Url = parts[0];
                        recitation.Folder = parts[0];
                        recitation.Language = parts[1];
                        recitation.Reciter = parts[2];
                        int.TryParse(parts[3], out recitation.Quality);
                        recitation.Name = recitation.Language + " - " + recitation.Reciter;
                        book.RecitationInfos.Add(parts[0], recitation);
                    }
                }
            }
        }
    }

    // translation books from http://tanzil.net
    public static void LoadTranslations(Book book)
    {
        try
        {
            string[] filenames = Directory.GetFiles(TRANSLATIONS_FOLDER + "/");
            foreach (string filename in filenames)
            {
                List<string> translated_lines = Data.LoadLines(filename);
                if (translated_lines != null)
                {
                    string translation = filename.Substring((TRANSLATIONS_FOLDER.Length + 1), filename.Length - (TRANSLATIONS_FOLDER.Length + 1) - 4);
                    if (translation == "metadata.txt") continue;
                    LoadTranslation(book, translation);
                }
            }
        }
        catch
        {
            // ignore error
        }
    }
    public static void LoadTranslation(Book book, string translation)
    {
        try
        {
            string[] filenames = Directory.GetFiles(TRANSLATIONS_FOLDER + "/");
            bool title_is_installed = false;
            foreach (string filename in filenames)
            {
                if (filename.Contains(translation))
                {
                    title_is_installed = true;
                    break;
                }
            }
            if (!title_is_installed)
            {
                File.Copy(OFFLINE_TRANSLATIONS_FOLDER + "/" + translation + ".txt", TRANSLATIONS_FOLDER + "/" + translation + ".txt");
            }

            filenames = Directory.GetFiles(TRANSLATIONS_FOLDER + "/");
            foreach (string filename in filenames)
            {
                if (filename.Contains(translation))
                {
                    List<string> translated_lines = Data.LoadLines(filename);
                    if (translated_lines != null)
                    {
                        if (book.TranslationInfos != null)
                        {
                            if (book.TranslationInfos.ContainsKey(translation))
                            {
                                for (int i = 0; i < Verse.MAX_NUMBER; i++)
                                {
                                    book.Verses[i].Translations[translation] = translated_lines[i];
                                }
                            }
                        }
                    }
                    break;
                }
            }
        }
        catch
        {
            // ignore error
        }
    }
    public static void UnloadTranslation(Book book, string translation)
    {
        try
        {
            string[] filenames = Directory.GetFiles(TRANSLATIONS_FOLDER + "/");
            foreach (string filename in filenames)
            {
                if (filename.Contains(translation))
                {
                    if (book.TranslationInfos != null)
                    {
                        if (book.TranslationInfos.ContainsKey(translation))
                        {
                            for (int i = 0; i < Verse.MAX_NUMBER; i++)
                            {
                                book.Verses[i].Translations.Remove(translation);
                            }
                            book.TranslationInfos.Remove(translation);
                        }
                        break;
                    }
                }
            }
        }
        catch
        {
            // ignore error
        }
    }
    // useful for correcting translations later in sha Allah
    public static void SaveTranslation(Book book, string translation)
    {
        StringBuilder str = new StringBuilder();
        foreach (Verse verse in book.Verses)
        {
            str.AppendLine(verse.Translations[translation]);
        }
        string filename = TRANSLATIONS_FOLDER + "/" + translation + ".txt";
        SaveFile(filename, str.ToString());
    }

    // word meanings from http://qurandev.appspot.com - modified by Ali Adams
    public static void LoadWordMeanings(Book book)
    {
        string filename = OFFLINE_TRANSLATIONS_FOLDER + "/" + "en.wordbyword.txt";
        if (File.Exists(filename))
        {
            using (StreamReader reader = File.OpenText(filename))
            {
                while (!reader.EndOfStream)
                {
                    try
                    {
                        foreach (Verse verse in book.Verses)
                        {
                            string line = reader.ReadLine();
                            string[] parts = line.Split('\t');
                            if (parts.Length != verse.Words.Count) throw new Exception("LoadWordMeanings file format error.");

                            for (int i = 0; i < verse.Words.Count; i++)
                            {
                                verse.Words[i].Meaning = parts[i];
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("LoadWordMeanings: " + ex.Message);
                    }
                }
            }
        }
    }

    // uthmani roots by Ali Adams from emlaaei version of http://www.noorsoft.org version 0.9.1
    public static void LoadRootWords(Book book)
    {
        string filename = DATA_FOLDER + "/" + "root-words.txt";
        if (File.Exists(filename))
        {
            book.RootWords = new Dictionary<string, List<Word>>();
            using (StreamReader reader = File.OpenText(filename))
            {
                while (!reader.EndOfStream)
                {
                    try
                    {
                        string line = reader.ReadLine();
                        string[] parts = line.Split('\t');
                        if (parts.Length == 3)
                        {
                            string root = parts[0];
                            int count = int.Parse(parts[1]);
                            string[] addresses = parts[2].Split(';');

                            List<Word> root_words = new List<Word>();
                            foreach (string address in addresses)
                            {
                                string[] segments = address.Split(':');
                                if (segments.Length == 2)
                                {
                                    string[] segment_parts = segments[1].Split(',');
                                    foreach (string segment_part in segment_parts)
                                    {
                                        int verse_index = int.Parse(segments[0]);
                                        Verse verse = book.Verses[verse_index];
                                        if (verse != null)
                                        {
                                            if (verse.Words != null)
                                            {
                                                if (verse.Words.Count > 0)
                                                {
                                                    int word_number = int.Parse(segment_part);
                                                    Word root_word = null;
                                                    // THIS software now loads an already-uthmani word root list
                                                    // generated by the SaveRootWordsDictionary() below

                                                    //// update word_number from emlaaei to uthmani
                                                    //try
                                                    //{
                                                    //    // for all words after merged words decrement word_number
                                                    //    for (int i = 0; i < word_number - 1; i++)
                                                    //    {
                                                    //        // if previous words starts with يَٰ or وَيَٰ   
                                                    //        if (
                                                    //            (verse.Words[i].Text.StartsWith("يَٰ"))
                                                    //            ||
                                                    //            (verse.Words[i].Text.StartsWith("وَيَٰ"))
                                                    //            )
                                                    //        {
                                                    //            word_number--;
                                                    //        }

                                                    //        // also, if previous words equals to these exceptions
                                                    //        if (verse.Words[i].Text == "يَبْنَؤُمَّ") // 3 words in imlaaei
                                                    //        {
                                                    //            word_number--;
                                                    //            word_number--;
                                                    //        }
                                                    //        else if (verse.Words[i].Text == "فَإِلَّمْ") // 2 words in imlaaei
                                                    //        {
                                                    //            word_number--;
                                                    //        }
                                                    //        else if (verse.Words[i].Text == "هَٰٓأَنتُمْ") // 2 words in imlaaei
                                                    //        {
                                                    //            word_number--;
                                                    //        }
                                                    //        else if (verse.Words[i].Text == "وَأَلَّوِ") // 2 words in imlaaei
                                                    //        {
                                                    //            word_number--;
                                                    //        }
                                                    //        // "بَعْدَ" and "مَا" to become "بَعْدَمَا"    // 2 words in imlaaei 
                                                    //        else if (verse.Words[i].Text == "بَعْدَ")
                                                    //        {
                                                    //            if (verse.Words.Count > (i + 1))
                                                    //            {
                                                    //                if (verse.Words[i + 1].Text == "مَا")
                                                    //                {
                                                    //                    word_number--;
                                                    //                }
                                                    //            }
                                                    //        }
                                                    //        else if ((root == "ما") && (verse.Words[word_number - 1].Text == "بَعْدَ"))
                                                    //        {
                                                    //            word_number--;
                                                    //        }
                                                    //    }
                                                    //}
                                                    //catch
                                                    //{
                                                    //    throw new Exception("Root word location cannot be corrected automatically.");
                                                    //}
                                                    if ((word_number > 0) && (word_number <= verse.Words.Count))
                                                    {
                                                        root_word = verse.Words[word_number - 1];
                                                        if (root_word != null)
                                                        {
                                                            root_words.Add(root_word);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }

                            if (!book.RootWords.ContainsKey(root))
                            {
                                book.RootWords.Add(root, root_words);
                            }
                        }
                        else
                        {
                            // skip reading copyright notice;
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("LoadRootWords: " + ex.Message);
                    }
                }
            }
        }
    }

    // word and its roots reverse-extracted from above by Ali Adams
    public static void LoadWordRoots(Book book)
    {
        // Id	Chapter	Verse	Word	Text	Roots
        string filename = DATA_FOLDER + "/" + "word-roots.txt";
        if (File.Exists(filename))
        {
            using (StreamReader reader = File.OpenText(filename))
            {
                while (!reader.EndOfStream)
                {
                    try
                    {
                        foreach (Verse verse in book.Verses)
                        {
                            for (int i = 0; i < verse.Words.Count; i++)
                            {
                                string line = reader.ReadLine();
                                string[] parts = line.Split('\t');

                                if (parts.Length == 6)
                                {
                                    string text = parts[4];
                                    string[] subparts = parts[5].Split('|');
                                    verse.Words[i].Roots = new List<string>(subparts);
                                }
                                else
                                {
                                    throw new Exception("LoadWordRoots: " + "Invalid file format.");
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("LoadWordRoots: " + ex.Message);
                    }
                }
            }
        }
    }

    // load book with Verse.MAX_NUMBER lines and simplify it on the fly
    // load book with Verse.MAX_NUMBER lines and simplify it on the fly
    public static Book LoadAndSimplifyBook(string filename, SimplificationSystem simplification_system)
    {
        Book book = null;
        if (File.Exists(filename))
        {
            using (StreamReader reader = File.OpenText(filename))
            {
                string original_content = reader.ReadToEnd();
                string simplified_content = simplification_system.SimplifyText(original_content);

                // 100 extra lines for tnzil copyrights, etc.
                simplified_content = simplified_content.Replace("\r\n", "\n");
                string[] simplified_lines = simplified_content.Split('\n');

                List<Verse> verses = new List<Verse>();
                int i = 0;
                foreach (string line in simplified_lines)
                {
                    if ((line.Length > 0) && (!line.StartsWith("#")))
                    {
                        Verse verse = new Verse(i + 1, line);
                        verses.Add(verse);
                        i++;
                    }
                }

                string title = Path.GetFileNameWithoutExtension(filename);
                book = new Book(title, verses);
            }
        }
        return book;
    }
    public static void SaveBook(Book book, string filename)
    {
        StringBuilder str = new StringBuilder();
        foreach (Verse verse in book.Verses)
        {
            str.AppendLine(verse.Text);
        }
        SaveFile(filename, str.ToString());
    }

    // help methods
    public static List<string> LoadLines(string filename)
    {
        List<string> result = new List<string>();
        if (File.Exists(filename))
        {
            using (StreamReader reader = File.OpenText(filename))
            {
                string line = "";
                while ((line = reader.ReadLine()) != null)
                {
                    result.Add(line);
                }
            }
        }
        return result;
    }
    public static string LoadFile(string filename)
    {
        StringBuilder str = new StringBuilder();
        if (File.Exists(filename))
        {
            using (StreamReader reader = File.OpenText(filename))
            {
                string line = "";
                while ((line = reader.ReadLine()) != null)
                {
                    str.AppendLine(line);
                }
            }
        }
        return str.ToString();
    }
    public static void SaveFile(string filename, string content)
    {
        try
        {
            using (StreamWriter writer = new StreamWriter(filename, false, Encoding.Unicode))
            {
                writer.Write(content);
            }
        }
        catch
        {
            // silence IO error in case running from read-only media (CD/DVD)
        }
    }
}
